#include "stdafx.h"
#include "Level.h"
#include "HUDManager.h"
#include "UIGameDM.h"
#include "xrServer.h"
#include "game_sv_mp.h"
#include "spectator.h"
#include "Actor.h"
#include "game_cl_base.h"
#include "game_cl_mp.h"
#include <xrCore/stream_reader.h>
#include "Message_Filter.h"

void CLevel::PrepareToSaveDemo		()
{
	R_ASSERT(!m_DemoPlay);
	string_path demo_name = "";
	string_path demo_path;
	SYSTEMTIME Time;
	GetLocalTime		(&Time);
	sprintf_s			(demo_name, "xray_%02d-%02d-%02d_%02d-%02d-%02d.demo",
		Time.wMonth,
		Time.wDay,
		Time.wYear,
		Time.wHour,
		Time.wMinute,
		Time.wSecond
	);
	Msg					("Demo would be stored in - %s", demo_name);
	FS.update_path      (demo_path, "$logs$", demo_name);
	m_writer			= FS.w_open(demo_path);
	m_DemoSave			= TRUE;
}

bool CLevel::PrepareToPlayDemo		(shared_str const & file_name)
{
	R_ASSERT(!m_DemoSave);
	m_reader	= FS.rs_open("$logs$", file_name.c_str());
	if (!m_reader)
	{
		Msg("ERROR: failed to open file [%s] to play demo...", file_name.c_str());
		return false;
	}
	if (!LoadDemoHeader())
	{
		Msg("ERROR: bad demo file...");
		return false;
	}
	m_DemoPlay		= TRUE;
	return true;
}

void CLevel::StopSaveDemo()
{
	if (m_writer)
	{
		FS.w_close(m_writer);
	}
}


void CLevel::StartPlayDemo()
{
	R_ASSERT(IsDemoPlay() && !m_DemoPlayStarted);

	m_current_spectator	= NULL;
	m_DemoPlayStarted	= TRUE;
	m_StartGlobalTime	= Device.dwTimeGlobal;
	Msg("! ------------- Demo Started ------------");

	//if using some filter ...
	/*message_filter* tmp_msg_filter = GetMessageFilter();
	if (tmp_msg_filter)
	{
		tmp_msg_filter->filter(M_GAMEMESSAGE, GAME_EVENT_ROUND_STARTED,
			tmp_msg_filter->m_onround_start_pause);
		string_path demo_msg_path;
		FS.update_path(demo_msg_path, "$logs$", "dbg_msg.log");
		tmp_msg_filter->dbg_set_message_log_file(demo_msg_path);
	}*/
}

void CLevel::StopPlayDemo()
{
	if (m_reader)
	{
		FS.r_close			(m_reader);
		m_reader			= NULL;
		m_DemoPlayStarted	= FALSE;
		m_DemoPlayStoped	= TRUE;
	}
	Msg("! ------------- Demo Stoped ------------");
}

void CLevel::RestartPlayDemo()
{
	StopPlayDemo	();
	MakeReconnect	();
}

void CLevel::StartSaveDemo(shared_str const & server_options)
{
	R_ASSERT(IsDemoSave() && !m_DemoSaveStarted);

	SaveDemoHeader		(server_options);
	m_DemoSaveStarted	= TRUE;
}

void CLevel::SaveDemoHeader(shared_str const & server_options)
{
	strncpy_s(m_demo_header.m_server_options, server_options.c_str(), server_options.size());
	m_demo_header.m_time_global			= Device.dwTimeGlobal;
	m_demo_header.m_time_server			= timeServer();
	m_demo_header.m_time_delta			= timeServer_Delta();
	m_demo_header.m_time_delta_user		= net_TimeDelta_User;
	m_writer->w(&m_demo_header, sizeof(m_demo_header));
}
void CLevel::SavePacket(NET_Packet& packet)
{
	m_writer->w_u32	(Device.dwTimeGlobal - m_demo_header.m_time_global);
	m_writer->w_u32	(packet.timeReceive);
	m_writer->w_u32	(packet.B.count);
	m_writer->w		(packet.B.data, packet.B.count);
}

bool CLevel::LoadDemoHeader	()
{
	R_ASSERT(m_reader);
	m_reader->r(&m_demo_header, sizeof(m_demo_header));
	return (m_reader->elapsed() >= sizeof(DemoPacket));
}

bool CLevel::LoadPacket		(NET_Packet & dest_packet, u32 global_time_delta)
{
	if (!m_reader)
		return false;
	u32 old_pos		= m_reader->tell();
	DemoPacket		tmp_hdr;
	m_reader->r		(&tmp_hdr, sizeof(DemoPacket));
	if ( map_data.m_sended_map_name_request ? /// ???
		(tmp_hdr.m_time_global_delta <= global_time_delta) :
		(tmp_hdr.m_time_global_delta < global_time_delta))
	{
		R_ASSERT2	(tmp_hdr.m_packet_size < NET_PacketSizeLimit, "bad demo packet");
		m_reader->r	(dest_packet.B.data, tmp_hdr.m_packet_size);
		dest_packet.B.count		= tmp_hdr.m_packet_size;
		dest_packet.timeReceive = tmp_hdr.m_timeReceive; //not used ..
		dest_packet.r_pos		= 0;
		if (m_reader->elapsed() <= sizeof(DemoPacket))
		{
			StopPlayDemo();
		}
		return true;
	} 
	m_reader->seek(old_pos);
	return false;
}
void CLevel::SimulateServerUpdate()
{
	u32 tdelta = Device.dwTimeGlobal - m_StartGlobalTime;
	NET_Packet tmp_packet;
	while (LoadPacket(tmp_packet, tdelta))
	{
		if (m_msg_filter)
			m_msg_filter->check_new_data(tmp_packet);
		IPureClient::OnMessage(tmp_packet.B.data, tmp_packet.B.count);
	}
}



void CLevel::SpawnDemoSpectator()
{
	R_ASSERT(Server && Server->game);
	m_current_spectator = NULL;
	game_sv_mp*	tmp_sv_game		= smart_cast<game_sv_mp*>(Server->game);
	game_cl_mp*	mp_cl_game		= smart_cast<game_cl_mp*>(Level().game);

	CSE_Spectator* specentity = smart_cast<CSE_Spectator*>(
		tmp_sv_game->spawn_begin("spectator"));
	R_ASSERT						(specentity);
	mp_cl_game->local_player		= mp_cl_game->createPlayerState();
	strcpy_s						(mp_cl_game->local_player->name, "demo_spectator");
	specentity->set_name_replace	(mp_cl_game->local_player->name);
	specentity->s_flags.assign		(M_SPAWN_OBJECT_LOCAL | M_SPAWN_OBJECT_ASPLAYER | M_SPAWN_OBJECT_PHANTOM); //M_SPAWN_OBJECT_PHANTOM is ONLY to indicate thath this is a fake spectator
	tmp_sv_game->assign_RP			(specentity, Level().game->local_player);
	
	g_sv_Spawn						(specentity);
	
	F_entity_Destroy				(specentity);
}

void CLevel::SetDemoSpectator(CObject* spectator)
{
	R_ASSERT2	(smart_cast<CSpectator*>(spectator),
		"tried to set not an spectator object to demo spectator");
	m_current_spectator = spectator;
}

float CLevel::GetDemoPlayPos() const
{
	if (!m_reader)
		return 1.f;
	if (m_reader->eof())
		return 1.f;
	
	return ( float(m_reader->tell()) / float(m_reader->length()) );
}

message_filter*	 CLevel::GetMessageFilter()
{
	if (m_msg_filter)
		return m_msg_filter;
	m_msg_filter = new message_filter();
	return m_msg_filter;
}
/*
void CLevel::SetDemoPlayPos(float const pos)
{
	if (!IsDemoPlayStarted())
	{
		Msg("! ERROR: demo play not started");
		return;
	}
	if (pos > 1.f)
	{
		Msg("! ERROR: incorect demo play position");
		return;
	}
	float cur_pos = GetDemoPlayPos();
	if (cur_pos >= pos)
	{
		Msg("! demo play position must be greater than current position");
		return;
	}
	
	u32 old_file_pos = m_reader->tell();

	u32				file_pos = u32(float(m_reader->length()) * pos);
	if (file_pos <= old_file_pos)
	{
		Msg("! demo play position already at the current point");
		return;
	}

	DemoPacket		tmp_hdr;
	u32				time_shift = 0;
	
	while (m_reader->tell() < file_pos)
	{
		m_reader->r		(&tmp_hdr, sizeof(DemoPacket));
		m_reader->seek	(m_reader->tell() + tmp_hdr.m_packet_size);
		time_shift		+= tmp_hdr.m_time_global_delta;
	}
	m_StartGlobalTime	-= time_shift;
	m_rewind			= TRUE;
	m_reader->seek		(old_file_pos);
}*/

float CLevel::GetDemoPlaySpeed() const
{
	return Device.time_factor();
}
#define MAX_PLAY_SPEED 8.f
void CLevel::SetDemoPlaySpeed(float const time_factor)
{
	if (!IsDemoPlayStarted())
	{
		Msg("! ERROR: demo play not started");
		return;
	}
	if (time_factor > MAX_PLAY_SPEED)
	{
		Msg("! Sorry, maximum play speed is: %1.1f", MAX_PLAY_SPEED);
		return;
	}
	Device.time_factor(time_factor);
}